Android UI と OpenGL レンダラの共存 ( Android OpenGL フレームワーク “Rajawali” と戯れる #09 )
Android OpenGL フレームワーク "Rajawali" と戯れるシリーズ
第 09 回目は、Android 標準のユーザーインターフェイス ( 以後 UI ) と OpenGL レンダラとの共存について解説します。
レイアウトの使用
Rajawali の基本アクティビティクラスである RajawaliFragmentActivity 上には、Android 標準の UI を配置することが可能です。厳密には RajawaliFragmentActivity が保持する FrameLayout(mLayout) に任意のレイアウトを addView() するという実装により実現できます。処理のすべてを Java のコードで記述することも可能ですが、LayoutInflater クラスを使用することで、レイアウト XML を使用したレイアウトも可能です。
RajawaliFragmentActivity サブクラス内における実装例
LayoutInflater inflater = LayoutInflater.from(this); LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.main, mLayout, false); //main.xml mLayout.addView(layout);
出力結果
以下のサンプルは、RajawaliFragmentActivity の FrameLayout に LinearLayout を追加して、LinearLayout 内にて定義済みのボタンとシークバーで 3D オブジェクトのパラメータを調整するものです。シークバーを操作するとき、値が常に更新されていることが確認できます。
ムービー
キャプチャ
ソース
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/button" /> <SeekBar android:id="@+id/xSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="0" android:max="359" /> <SeekBar android:id="@+id/ySeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="0" android:max="359" /> <SeekBar android:id="@+id/zSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="0" android:max="359" /> <TextView android:id="@+id/textView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/textView" android:textAppearance="?android:attr/textAppearanceLarge" /> </LinearLayout>
MainActivity.java
package jp.classmethod.sample; import javax.microedition.khronos.opengles.GL10; import rajawali.RajawaliFragmentActivity; import rajawali.animation.mesh.VertexAnimationObject3D; import rajawali.lights.DirectionalLight; import rajawali.parser.MD2Parser; import rajawali.renderer.RajawaliRenderer; import android.content.Context; import android.content.res.Resources; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; /** * MainActivity */ public class MainActivity extends RajawaliFragmentActivity { /** @private */ private Lesson07_01Renderer mRenderer; /** @private */ private TextView textView; /** @private */ private Button button; /** @private */ private SeekBar xSeekBar; /** @private */ private SeekBar ySeekBar; /** @private */ private SeekBar zSeekBar; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRenderer = new Lesson07_01Renderer(this); mRenderer.setSurfaceView(mSurfaceView); setRenderer(mRenderer); LayoutInflater inflater = LayoutInflater.from(this); LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.main, mLayout, false); mLayout.addView(layout); textView = (TextView)layout.findViewById(R.id.textView); OnClickListener clickListener = new OnClickListener() { @Override public void onClick(View v) { textView.setText("Swing negi!!"); mRenderer.swingNegi(); } }; button = (Button)layout.findViewById(R.id.button); button.setOnClickListener(clickListener); OnSeekBarChangeListener seekBarChangeListener = new OnSeekBarChangeListener() { @Override /** トラッキング開始 */ public void onStartTrackingTouch(SeekBar seekBar) { } @Override /** トラッキング中 */ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { setRotationBySeekBar(); } @Override /** トラッキング終了 */ public void onStopTrackingTouch(SeekBar seekBar) { setRotationBySeekBar(); } }; xSeekBar = (SeekBar)layout.findViewById(R.id.xSeekBar); xSeekBar.setOnSeekBarChangeListener(seekBarChangeListener); ySeekBar = (SeekBar)layout.findViewById(R.id.ySeekBar); ySeekBar.setOnSeekBarChangeListener(seekBarChangeListener); zSeekBar = (SeekBar)layout.findViewById(R.id.zSeekBar); zSeekBar.setOnSeekBarChangeListener(seekBarChangeListener); } /** シークバーの値をレンダラに反映 */ private void setRotationBySeekBar() { float rotX = (float)xSeekBar.getProgress(); float rotY = (float)ySeekBar.getProgress(); float rotZ = (float)zSeekBar.getProgress(); mRenderer.setRotation(rotX, rotY, rotZ); textView.setText("rotX : " + Float.toString(rotX) + "\n" + "rotY : " + Float.toString(rotY) + "\n" + "rotZ : " + Float.toString(rotZ) ); } /** RajawaliRenderer のサブクラス */ private class Lesson07_01Renderer extends RajawaliRenderer { /** 3D オブジェクト */ protected VertexAnimationObject3D mObj; /** コンストラクタ */ public Lesson07_01Renderer(Context context) { super(context); setFrameRate(60); setBackgroundColor(0x999999); } @Override /** シーン初期化 */ protected void initScene() { Resources r = mContext.getResources(); DirectionalLight light = new DirectionalLight(); light.setPower(1.5f); light.setColor(0xff9900); light.setPosition(0f, 3f, -1f); MD2Parser parser = new MD2Parser(r, mTextureManager, R.raw.r_miku_md2); parser.parse(); mObj = (VertexAnimationObject3D)parser.getParsedAnimationObject(); mObj.addLight(light); mObj.setY(-.75f); mObj.setScale(.5f); addChild(mObj); } @Override /** フレーム描画 */ public void onDrawFrame(GL10 glUnused) { super.onDrawFrame(glUnused); } /** 葱振り */ public void swingNegi() { mObj.play("walk"); } /** 3D オブジェクトの回転 */ public void setRotation(float rotX, float rotY, float rotZ) { mObj.setRotation(rotX, rotY, rotZ); } } }